package com.java.sample.encrypt.ecdh;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Arrays;

/**
 * 对应前端的解密逻辑
 */
public class AESGCMCompatibleUtil {

    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/GCM/NoPadding";
    private static final int TAG_LENGTH = 128; // 128位认证标签
    private static final int IV_LENGTH = 12;   // 12字节IV (GCM推荐)

    /**
     * 解密HTML端加密的数据（完全兼容Web Crypto API格式）
     * @param encryptedData Base64编码的加密数据（包含IV和密文+认证标签）
     * @param keyBytes 原始密钥字节数组（必须是16, 24或32字节）
     * @return 解密后的原始字符串
     */
    public static String decrypt(String encryptedData, byte[] keyBytes) {
        try {
            // 1. Base64解码
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);

            // 验证数据长度至少包含IV和最小密文
            if (encryptedBytes.length < IV_LENGTH + 16) {
                throw new IllegalArgumentException("加密数据太短，至少需要28字节(IV+最小密文+标签)");
            }

            // 2. 分离IV和密文（前12字节是IV，后面是实际密文+16字节认证标签）
            byte[] iv = Arrays.copyOfRange(encryptedBytes, 0, IV_LENGTH);
            byte[] ciphertextWithTag = Arrays.copyOfRange(encryptedBytes, IV_LENGTH, encryptedBytes.length);

            // 3. 初始化解密器
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM);
            GCMParameterSpec params = new GCMParameterSpec(TAG_LENGTH, iv);

            cipher.init(Cipher.DECRYPT_MODE, keySpec, params);

            // 4. 执行解密（doFinal会自动处理认证标签）
            byte[] decryptedBytes = cipher.doFinal(ciphertextWithTag);
            return new String(decryptedBytes, StandardCharsets.UTF_8);

        } catch (Exception e) {
            throw new RuntimeException("AES-GCM解密失败: " + e.getMessage(), e);
        }
    }

    /**
     * 加密数据（与Web Crypto API兼容）
     * @param data 要加密的原始数据
     * @param keyBytes 原始密钥字节数组
     * @return Base64编码的加密数据（包含IV和密文+认证标签）
     */
    public static String encrypt(String data, byte[] keyBytes) {
        try {
            // 1. 生成随机IV
            byte[] iv = new byte[IV_LENGTH];
            java.security.SecureRandom random = new java.security.SecureRandom();
            random.nextBytes(iv);

            // 2. 初始化加密器
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM);
            GCMParameterSpec params = new GCMParameterSpec(TAG_LENGTH, iv);

            cipher.init(Cipher.ENCRYPT_MODE, keySpec, params);

            // 3. 执行加密（doFinal会自动生成16字节认证标签并附加到密文后）
            byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

            // 4. 组合IV和密文+标签
            byte[] combined = new byte[iv.length + encryptedBytes.length];
            System.arraycopy(iv, 0, combined, 0, iv.length);
            System.arraycopy(encryptedBytes, 0, combined, iv.length, encryptedBytes.length);

            // 5. Base64编码
            return Base64.getEncoder().encodeToString(combined);

        } catch (Exception e) {
            throw new RuntimeException("AES-GCM加密失败: " + e.getMessage(), e);
        }
    }

    /**
     * 从Base64字符串解码密钥
     */
    public static byte[] keyFromBase64(String keyBase64) {
        return Base64.getDecoder().decode(keyBase64);
    }

    /**
     * 从共享密钥字节数组派生AES密钥（使用SHA-256哈希确保正确长度）
     */
    public static byte[] deriveAesKeyFromSharedSecret(byte[] sharedSecret) {
        try {
            java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
            return digest.digest(sharedSecret);
        } catch (Exception e) {
            throw new RuntimeException("密钥派生失败", e);
        }
    }

    /**
     * 测试方法：验证Java与HTML端的兼容性
     */
    public static void main(String[] args) {
        try {
            System.out.println("=== Java与HTML AES-GCM兼容性测试 ===\n");

            // 模拟一个共享密钥（在实际应用中来自ECDH计算）
            byte[] sharedSecret = "my_shared_secret_123".getBytes(StandardCharsets.UTF_8);
            byte[] aesKey = deriveAesKeyFromSharedSecret(sharedSecret);

            System.out.println("AES密钥长度: " + aesKey.length + " 字节");

            // 测试数据
            String originalText = "Hello, AES-GCM加密测试!";
            System.out.println("原始文本: " + originalText);

            // 加密
            String encrypted = encrypt(originalText, aesKey);
            System.out.println("加密结果: " + encrypted);

            // 解密
            String decrypted = decrypt(encrypted, aesKey);
            System.out.println("解密结果: " + decrypted);

            // 验证一致性
            System.out.println("加解密是否一致: " + originalText.equals(decrypted));

            // 分析加密数据格式
            byte[] encryptedBytes = Base64.getDecoder().decode(encrypted);
            System.out.println("\n加密数据格式分析:");
            System.out.println("总长度: " + encryptedBytes.length + " 字节");
            System.out.println("IV长度: " + IV_LENGTH + " 字节");
            System.out.println("密文+标签长度: " + (encryptedBytes.length - IV_LENGTH) + " 字节");

        } catch (Exception e) {
            System.err.println("测试失败: " + e.getMessage());
            e.printStackTrace();
        }

        // 解密 html 数据
//        try {
//            // 从HTML端获取的加密数据
//            String encryptedDataFromHTML = "你的Base64加密数据";
//
//            // 你的共享密钥（来自ECDH计算）
//            byte[] sharedSecret = ...; // 你的ECDH共享密钥字节数组
//
//            // 从共享密钥派生AES密钥
//            byte[] aesKey = AESGCMCompatibleUtil.deriveAesKeyFromSharedSecret(sharedSecret);
//
//            // 解密
//            String decryptedData = AESGCMCompatibleUtil.decrypt(encryptedDataFromHTML, aesKey);
//            System.out.println("解密结果: " + decryptedData);
//
//        } catch (Exception e) {
//            System.err.println("解密失败: " + e.getMessage());
//            e.printStackTrace();
//        }
    }

}